/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.etherframework.behaviour.rules.core
{
	import org.etherframework.behaviour.rules.context.IContext;
	import org.etherframework.behaviour.rules.controls.IInteractive;
	import org.etherframework.behaviour.rules.core.Control;
	import org.etherframework.behaviour.rules.core.IControl;
	import org.etherframework.behaviour.rules.util.ContextResolver;
	import org.etherframework.behaviour.rules.util.DescriptorParser;
	
	import flash.utils.Dictionary;
	
	import mx.core.mx_internal;
	
	use namespace mx_internal;
	
	[DefaultProperty("children")]
	[Exclude(name="isDocument", kind="property")]
	
	public class Chain extends Control implements IChain
	{
		[Bindable]
		[Inspectable(defaultValue="true")]
		public var enabled:Boolean = true;
		
		private var document:Object;
		
		private var inited:Boolean = false;
		
		public function Chain()
		{
			super();
		}
		
		public function initialized(document:Object, id:String):void
		{
			this.document = document;
			if (id && (id.indexOf("_") != 0))
				this.id = id;
		}
		
		override public function initialize():void
		{
			if (inited)
				return;
			
			inited = true;
			// Currently only if document has bindings we can try to guess either it is document or not.
			_isDocument = ContextResolver.isBindable(descriptor.type);
			
			ContextResolver.register(this, null, function(value:IContext):void {_lastContext = value;},
									function(value:IContext):void {_localContext = value;}, 
									function(value:*):void {_reason = value;});
			ContextResolver.enableBindingsByObject(this, descriptor.type, false);
			
			if (_children.length)
			{
				var child:IControl;
				var childrenLen:int = _children.length;
				
				if (_isDocument && childrenLen)
				{
					// FIXME: Should assign all uid. 
					DescriptorParser.execute(this, descriptor.type);
					// Should assign proper descriptor.document/owner/parent.
					DescriptorParser.traverseChildren(_children, this, this, this);
				}
				
				for (var i:int = 0; i < childrenLen; ++i)
				{
					child = _children[i] as IControl;
					
					if (child) 
					{
						child.initialize();
					}
				}
			}
			else if (_isDocument)
			{
				var items:Array = [];
				var map:Dictionary = DescriptorParser.execute(this, descriptor.type);
				
				for (var member:Object in map)
				{
					if (member is IControl)
					{
						items.push(member);
						member.initialize();
					}
				}
				
				children = items; 
			}
		}
		
		private var _isDocument:Boolean = false;
		
		public function get isDocument():Boolean
		{
			return _isDocument;
		}
		
		private var _children:Array = [];
		
		[ArrayElementType("org.etherframework.behaviour.rules.controls.IInteractive")]
		[Inspectable(category="General", arrayType="org.etherframework.behaviour.rules.controls.IInteractive")]
		public function get children():Array
		{
			return _children;
		}
		
		public function set children(value:Array):void
		{
			_children = value;
		}
		
		[Bindable(event="propertyChange")]
		override public function get context():IContext
		{
			return super.context;
		}
		
		override public function set context(value:IContext):void
		{
			if (!value)
				return;
			
			super.context = value;
		}
		
		private var _localContext:IContext;
		
		[Bindable(event="propertyChange")]
		public function get localContext():IContext
		{
			return _localContext;
		}
		
		private var _lastContext:IContext;
		
		[Bindable(event="propertyChange")]
		public function get lastContext():IContext
		{
			return _lastContext;
		}
		
		private var _reason:*;
		
		[Bindable(event="propertyChange")]
		public function get reason():*
		{
			return _reason;
		}
		
	}
}